﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml;
using System.IO;
using System.Diagnostics;

namespace SmoothStreaming.PerformanceTesting
{
    public class ManifestParser
    {
        public TimeSpan? ManifestDownloadTime { get; private set; }

        public IEnumerable<StreamIndex> ParseManifest(Uri manifestUri)
        {
            List<SmoothStreamChunk> chunkList = new List<SmoothStreamChunk>();
            Stopwatch sw = new Stopwatch();
            sw.Start();
            string manifestXml = new WebClient().DownloadString(manifestUri);
            sw.Stop();

            ManifestDownloadTime = sw.Elapsed;
            
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(manifestXml);

            var ssMediaNode = xmlDoc.ChildNodes.Cast<XmlNode>().Where(n => n.Name == "SmoothStreamingMedia").FirstOrDefault();

            List<StreamIndex> streams = new List<StreamIndex>();

            var streamIndexNodes = ssMediaNode.ChildNodes.Cast<XmlNode>().Where(n => n.Name == "StreamIndex").ToList();

            foreach (var sIndexNode in streamIndexNodes)
            {
                StreamIndex si = new StreamIndex();

                si.StreamType = sIndexNode.Attributes["Type"].InnerText;
                si.Url = sIndexNode.Attributes["Url"].InnerText;

                if (!si.Url.StartsWith("http"))
                {
                    si.Url = new Uri(manifestUri, si.Url).ToString();
                }

                var qualityLevelNodes = sIndexNode.ChildNodes.Cast<XmlNode>().Where(n => n.Name == "QualityLevel").ToList();

                foreach (var qlNode in qualityLevelNodes)
                {
                    int bitrate = Int32.Parse(qlNode.Attributes["Bitrate"].InnerText);
                    si.AddBitrate(bitrate);
                }

                var chunkNodes = sIndexNode.ChildNodes.Cast<XmlNode>().Where(n => n.Name == "c").ToList();

                double chunkDurationIndex = 0;

                foreach (var cNode in chunkNodes)
                {
                    int chunkDuration = Int32.Parse(cNode.Attributes["d"].InnerText);

                    if (chunkDurationIndex == 0)
                    {
                        foreach (var br in si.Bitrates)
                        {
                            si.AddChunk(0, chunkDuration, br);
                        }
                    }

                    if (cNode == chunkNodes.Last())
                    {
                        continue;
                    }

                    chunkDurationIndex += chunkDuration;

                    foreach (var br in si.Bitrates)
                    {
                        si.AddChunk(chunkDurationIndex, chunkDuration, br);
                    }
                }

                streams.Add(si);
            }

            return streams;
        }
    }
}
